package com.ypj.rpc.codec;

import com.ypj.rpc.entity.RpcRequest;
import com.ypj.rpc.entity.RpcResponse;
import com.ypj.rpc.enumeration.PackageType;
import com.ypj.rpc.enumeration.RpcError;
import com.ypj.rpc.exception.RpcException;
import com.ypj.rpc.serializer.CommonSerializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 自定义协议：
 * +---------------+---------------+-----------------+-------------+
 * |  Magic Number |  Package Type | Serializer Type | Data Length |
 * |    4 bytes    |    4 bytes    |     4 bytes     |   4 bytes   |
 * +---------------+---------------+-----------------+-------------+
 * |                          Data Bytes                           |
 * |                   Length: ${Data Length}                      |
 * +---------------------------------------------------------------+
 * 魔数，表示一个协议包
 * Package：标识是请求还是响应
 * Serializer：标识使用的序列化器
 * Data Length：数据长度防止粘包
 */
@Slf4j
public class CommonDecoder extends ReplayingDecoder {

    private static final int MAGIC_NUMBER = 0xCAFEBABE;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int magic=in.readInt();
        if (magic!=MAGIC_NUMBER){
            log.error("无法识别的协议包：{}",magic);
            throw new RpcException(RpcError.UNKNOWN_PROTOCOL.getMessage());
        }
        int packageCode=in.readInt();
        Class<?> packageClass;
        if (packageCode== PackageType.REQUEST_PACK.getCode()){
            packageClass= RpcRequest.class;
        }else if (packageCode==PackageType.RESPONSE_PACK.getCode()){
            packageClass=RpcResponse.class;
        }else{
            log.error("无法识别数据包类型：{}",packageCode);
            throw new RpcException(RpcError.UNKNOWN_PACKAGE_TYPE.getMessage());
        }
        int serializerCode=in.readInt();
        CommonSerializer serializer=CommonSerializer.getByCode(serializerCode);
        if (serializer==null){
            log.error("无法识别(反)序列化器：{}",serializerCode);
            throw new RpcException(RpcError.UNKNOWN_SERIALIZER.getMessage());
        }
        int length=in.readInt();
        byte[] content=new byte[length];
        in.readBytes(content);
        Object obj = serializer.deserialize(content, packageClass);
        out.add(obj);

    }
}
